package edu.ccut.saturn.studio.logic.model.drop;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.internal.core.JarEntryFile;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import edu.ccut.saturn.studio.core.exception.XMLException;
import edu.ccut.saturn.studio.core.util.xml.SaturnW3CUtil;
import edu.ccut.saturn.studio.logic.model.Shape;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnComponentNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnParameter;
import edu.ccut.saturn.studio.logic.model.xml.loader.ComponentNodeLoader;

public class ComponentDropHandler extends AbstarctDropHandler {
	private static final String COMPONENT_DROP_HANDLER_DESCRIPTION = "description";
	private static final String COMPONENT_DROP_HANDLER_TWO_DOT = "::";
	private static final String COMPONENT_DROP_HANDLER_KEY = "key";
	public static final String FILE_POSTFIX = ".component.xml";
	private static final String COMPONENT_DROP_HANDLER_NAME = "name";
	private static final String COMPONENT_DROP_HANDLER_NULL = "";
	private static final ComponentNodeLoader componentNodeLoader = new ComponentNodeLoader();

	public Shape getShape(String filePath, IProject project) {
		String symbolicName = super.getBundleName(project);
		Element root = null;
		try {
			root = SaturnW3CUtil.getDocument(filePath).getDocumentElement();
		} catch (XMLException e) {
			e.printStackTrace();
		}

		return getShape(root, symbolicName);
	}

	public Shape getShape(JarEntryFile jarEntryFile) {
		InputStream in = null;

		try {
			DocumentBuilderFactory domfac = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder dombuilder = domfac.newDocumentBuilder();

			in = (InputStream) jarEntryFile.getContents();

			Document doc = dombuilder.parse(in);
			String bundleName = super.getBundleNameFromJar(jarEntryFile);
			Element root = doc.getDocumentElement();

			return this.getShape(root, bundleName);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return null;
	}

	private Shape getShape(Element root, String symbolicName) {
		String keyValue = "";
		String name = "";
		String description = "";
		List<SaturnParameter> parameters = null;
		List component = SaturnW3CUtil.getChildrenByName(root,
				SaturnComponentNode.KEY_NODE_COMPONENT);
		for (int j = 0; j < component.size(); j++) {
			Node in = (Node) component.get(j);
			try {
				keyValue = in.getAttributes().getNamedItem(
						COMPONENT_DROP_HANDLER_KEY).getNodeValue();
			} catch (Exception e) {
			}
			try {
				name = in.getAttributes().getNamedItem(
						COMPONENT_DROP_HANDLER_NAME).getNodeValue();
			} catch (Exception e) {
			}
			try {
				parameters = this.getParameters(in);
			} catch (Exception e) {
			}
			for (Node n = in.getFirstChild(); n != null; n = n.getNextSibling()) {
				if (n.getNodeType() == Node.ELEMENT_NODE) {

					if (n.getNodeName().equals(
							COMPONENT_DROP_HANDLER_DESCRIPTION)) {
						try {
							description = n.getFirstChild().getNodeValue();
						} catch (Exception e) {
						}
					}
				}
			}
		}
		SaturnComponentNode saturnComponentNode = new SaturnComponentNode();
		// add
		// saturnComponentNode.setKey(getBundleName()
		// +COMPONENT_DROP_HANDLER_TWO_TOC+ keyValue);
		saturnComponentNode.setKey(symbolicName.trim() + "::" + keyValue);
		saturnComponentNode.setDescription(description);
		// saturnComponentNode.setKey(keyValue);
		saturnComponentNode.setName(name);
		saturnComponentNode.setParameters(parameters);
		return saturnComponentNode;
	}
	protected List<SaturnParameter> getParameters(Node node) {
		Node parametersNode = this
				.getChildNode(node, Shape.KEY_NODE_PARAMETERS);

		List<SaturnParameter> parameters = new ArrayList<SaturnParameter>();

		if (parametersNode != null) {
			List<Node> parameterNodes = this.getChildNodes(parametersNode,
					Shape.KEY_NODE_PARAMETER);

			for (Node parameterNode : parameterNodes) {
				parameters.add(this.getParameter(parameterNode));
			}
		}

		return parameters;
	}
	
	protected Node getChildNode(Node parentNode, String nodeKey) {
		NodeList children = parentNode.getChildNodes();

		for (int i = 0; i < children.getLength(); ++i) {
			Node child = children.item(i);

			if (child.getNodeName().equals(nodeKey)) {
				return child;
			}
		}

		return null;
	}

	protected List<Node> getChildNodes(Node parentNode, String nodeKey) {
		NodeList children = parentNode.getChildNodes();

		List<Node> childNodes = new ArrayList<Node>();

		for (int i = 0; i < children.getLength(); ++i) {
			Node child = children.item(i);

			if (child.getNodeName().equals(nodeKey)) {
				childNodes.add(child);
			}
		}

		return childNodes;
	}
	
	private SaturnParameter getParameter(Node parameterNode) {
		String id = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_ID);
		String name = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_NAME);
		String classType = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_CLASS_TYPE);
		String passingType = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_PASSING_TYPE);

		String valueKey = this.getNodeElementValue(parameterNode,
				Shape.KEY_PARAMETER_NODE_VALUE_KEY);
		String scope = this.getNodeElementValue(parameterNode,
				Shape.KEY_PARAMETER_NODE_SCOPE);
		String description = this.getNodeElementValue(parameterNode,
				Shape.KEY_PARAMETER_NODE_DESCRIPTION);

		SaturnParameter saturnParameter = new SaturnParameter();
		saturnParameter.setId(id);
		saturnParameter.setName(name);
		saturnParameter.setClassType(classType);
		saturnParameter.setPassingType(passingType);
		saturnParameter.setValueKey(valueKey);
		saturnParameter.setScope(scope);
		saturnParameter.setDescription(description);

		return saturnParameter;
	}
	protected String getNodeAttributeValue(Node node, String key) {
		Node attribute = node.getAttributes().getNamedItem(key);

		if (attribute != null) {
			return attribute.getNodeValue();
		}

		return COMPONENT_DROP_HANDLER_NULL;
	}

	protected String getNodeElementValue(Node node, String key) {
		NodeList childNodes = node.getChildNodes();

		for (int i = 0; i < childNodes.getLength(); ++i) {
			Node child = childNodes.item(i);
			if (child.getNodeName().equals(key)) {
				if (child.getFirstChild() != null) {
					return child.getFirstChild().getNodeValue();
				}

				return COMPONENT_DROP_HANDLER_NULL;
			}
		}

		return COMPONENT_DROP_HANDLER_NULL;
	}
}
